package me.itsoo.artemis.framework.repository.interceptor;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import me.itsoo.artemis.framework.core.util.AnnotationUtils;
import me.itsoo.artemis.framework.core.util.Assert;
import me.itsoo.artemis.framework.core.util.CollectionUtils;
import me.itsoo.artemis.framework.ioc.lang.Orders;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;

/**
 * OrderSorts
 *
 * @author zxy
 * @version 0.0.1
 * @since 2023/5/23
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class OrderSorts {

    /**
     * 拦截器列表排序（线程安全）
     *
     * @param sqlInterceptors List
     */
    public static synchronized void sort(Collection<SqlInterceptor> sqlInterceptors) {
        if (CollectionUtils.isNotEmpty(sqlInterceptors)) {
            final List<InnerWrapper> temp = new ArrayList<>(sqlInterceptors.size());
            for (SqlInterceptor si : sqlInterceptors) {
                temp.add(InnerWrapper.create(si, computeOrdered(si)));
            }

            temp.sort(Comparator.comparingInt(InnerWrapper::getOrdered).reversed());

            sqlInterceptors.clear();

            for (InnerWrapper iw : temp) {
                sqlInterceptors.add(iw.getSqlInterceptor());
            }
        }
    }

    /**
     * 计算排序号
     *
     * @param sqlInterceptor SqlInterceptor
     * @return int
     */
    private static int computeOrdered(SqlInterceptor sqlInterceptor) {
        if (sqlInterceptor instanceof Ordered) {
            final Ordered ordered = (Ordered) sqlInterceptor;
            return ordered.ordered();
        }

        final Orders ann = AnnotationUtils.findAnnotation(sqlInterceptor.getClass(), Orders.class);
        if (Objects.nonNull(ann)) {
            return ann.value();
        }

        return Orders.DEFAULT_VALUE;
    }

    /**
     * InnerWrapper
     */
    @Getter
    private static class InnerWrapper {

        private final SqlInterceptor sqlInterceptor;

        private final int ordered;

        private InnerWrapper(SqlInterceptor sqlInterceptor, int ordered) {
            this.sqlInterceptor = sqlInterceptor;
            this.ordered = ordered;
        }

        static InnerWrapper create(SqlInterceptor sqlInterceptor, int ordered) {
            Assert.notNull(sqlInterceptor, "'sqlInterceptor' cannot be null");
            return new InnerWrapper(sqlInterceptor, ordered);
        }
    }
}
